import React, {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import "../css/LeftMenu.less";
import {ConfigProvider, Input, Menu} from "antd";
import Config from "../../Config.tsx";
import {coreConnect} from "../../utils/StoreUtil.tsx";
import {loadMenuChild} from "../../services/MenuService.tsx";
import {isNumber, strToObject, treeEach, treeFilterMap, treeMapAsync} from "../../utils";
import {getLocale} from "../../../i18n/i18n.tsx";
import {useNavigate} from "react-router";
import {useTranslation} from "react-i18next";
import useStateRef from "../../customUse/useStateRef.tsx";
import {AxiosGet} from "../../services/HttpService.tsx";
import {getItem} from "../../services/LocalDataService.tsx";
import GlobalIcon from "../../global/GlobalIcon.tsx";

interface LeftMenuProps {
    menuId?: string,
    themeToken: any,
    selectMenuId: string,
    menuMap: any,
    dispatch: Function,
    isFold: boolean
}

const LeftMenu: FC<LeftMenuProps> = (props) => {
    const {t} = useTranslation();

    const navigateTo = useNavigate();

    const menuMap = useRef({});
    const menuCountMap = useRef({});
    const openMap = useRef([]);
    const allMenuRef = useRef([]);

    const [fold, setFold] = useState<boolean>(false),
        [menus, setMenus] = useState<any[]>(),
        [selectedKey, setSelectedKey] = useState<string>(),
        [openKeys, setOpenKeys] = useStateRef([], openMap);

    const loadMenuCount = useCallback(async (params: any = {}) => {
        const {countUrl, countParams = {}} = params;
        if (!countUrl) {
            return
        }
        const {data = {}} = await AxiosGet(countUrl, countParams);
        menuCountMap.current = {
            ...menuCountMap.current,
            ...data
        }
    }, [])

    const loadMenu = useCallback(async (menuId: string, params = props) => {
        const {menuMap = {}, dispatch} = params;
        if (menuMap[menuId]) {
            return menuMap[menuId]
        }
        const data = await loadMenuChild({parentId: menuId, menuType: "MENU"});
        dispatch({
            type: "menuReducer/createMenu",
            payload: data
        });
        return data
    }, []);

    const getLabel = useCallback((node: any) => {
        return (
            <div className="sf_core_left_menu_label">
                <span className="sf_core_left_menu_label_title">{node.label}</span>
                {isNumber(node.count) ? <span className="sf_core_left_menu_label_count">{node.count}</span> : null}
            </div>
        )
    }, [])

    const initMenu = useCallback(async () => {
        const {menuId = Config.rootMenuId} = props;
        const data = await loadMenu(menuId);
        const newMenus = await treeMapAsync(data, async (children: any[], item: any, parent: any) => {
            const operate = strToObject(item.operate);
            if (operate.countUrl) {
                await loadMenuCount(operate);
            }
            return {
                key: item.id,
                label: getLocale(item.zhCn, item.usEn, item.ptBr),
                labelCn: item.zhCn,
                labelEn: item.usEn,
                labelPt: item.ptBr,
                tabType: item.isOutside ? "iframe" : "tab",
                tabParams: {
                    url: item.url,
                    menuId: item.id,
                    ...operate
                },
                parentPath: parent ? [parent.id] : [],
                breadcrumb: [{
                    labelCn: item.zhCn,
                    labelEn: item.usEn,
                    labelPt: item.ptBr,
                }],
                icon: item.icon ? <GlobalIcon name={item.icon}/> : <span></span>,
                children: children && children.length > 0 ? children : null
            }
        });
        treeEach(newMenus, (node, parent) => {
            node.count = menuCountMap.current[node.key];
            node.popupClassName = "sf_core_left_menu_popup";
            node.parentPath = parent ? [...parent.parentPath, ...node.parentPath] : node.parentPath;
            node.breadcrumb = parent && parent.breadcrumb ? [...parent.breadcrumb, ...node.breadcrumb] : node.breadcrumb;
            node.label = getLabel(node);
            node.open = true;
            if (!node.children) {
                menuMap.current[node.key] = node;
            }
        });
        setMenus(newMenus);
        allMenuRef.current = newMenus;
        if (props.selectMenuId !== "home" && menuMap.current[props.selectMenuId]) {
            setOpenKeys(menuMap.current[props.selectMenuId].parentPath);
        }
    }, [props.menuMap, props.menuMap]);


    useEffect(() => {
        initMenu();
    }, [props.menuId]);

    const onAddMenu = useCallback((node: any) => {
        props.dispatch({
            type: "tabsReducer/addTabs",
            payload: {
                data: {
                    key: node.key,
                    label: node.label,
                    labelCn: node.labelCn,
                    labelEn: node.labelEn,
                    labelPt: node.labelPt,
                    tabType: node.tabType,
                    tabParams: node.tabParams,
                    breadcrumb: node.breadcrumb
                }
            }
        });
        let to = '/home/' + node.key;
        navigateTo(to);
        props.dispatch({
            type: "titleReducer/addTitleMap",
            payload: {
                key: to,
                value: {
                    titleCn: node.labelCn,
                    titleEn: node.labelEn,
                }
            }
        });
    }, []);

    const onSelect = useCallback(({item, key}) => {
        setSelectedKey(key);
        onAddMenu({
            key: key,
            label: getLocale(item.props.labelCn, item.props.labelEn, item.props.labelPt),
            labelCn: item.props.labelCn,
            labelEn: item.props.labelEn,
            labelPt: item.props.labelPt,
            tabType: item.props.tabType,
            tabParams: {
                ...item.props.tabParams,
                menuId: key
            },
            breadcrumb: item.props.breadcrumb
        });
    }, []);

    const onOpenChange = useCallback((openKeys: string[]) => {
        setOpenKeys(openKeys);
    }, [])

    const handleSearch = useCallback((value: string = "") => {
        const local = getItem(Config.localLang);
        const newMenu = treeFilterMap(allMenuRef.current, (node) => {
            let label = "";
            switch (local) {
                case "zh":
                    label = node.labelCn;
                    break;
                case "en":
                    label = node.labelEn;
                    break;
                case "pt":
                    label = node.labelPt;
                    break;
            }
            return label.indexOf(value) !== -1;
        });
        setMenus(newMenu);
    }, []);

    useEffect(() => {
        if (props.selectMenuId !== "home") {
            setSelectedKey(props.selectMenuId);
            menuMap.current[props.selectMenuId] && setOpenKeys([...new Set([...openMap.current, ...menuMap.current[props.selectMenuId].parentPath])]);
        }
    }, [props.selectMenuId]);

    useEffect(() => {
        setFold(props.isFold);
    }, [props.isFold]);

    const renderLeftMenu = useMemo(() => {
        if (!menus) {
            return
        }
        const isShowSearchMenu: boolean = Config.isShowSearchMenu;
        return (
            <ConfigProvider
                theme={{
                    token: {
                        "colorPrimary": props.themeToken.themeColor,
                        "fontSize": props.themeToken.fontSize,
                        "colorBgBase": props.themeToken.baseBgColor,
                        "colorTextBase": props.themeToken.menuFontColor,
                        "borderRadius": props.themeToken.borderRadius,
                    }
                }}
            >
                <div className={"sf_core_left_menu"}>
                    {isShowSearchMenu && !fold ? <Input.Search
                        size="small"
                        className={"sf_core_left_menu_search"}
                        placeholder={t("searchMenu")}
                        onSearch={handleSearch}
                    /> : null}
                    <Menu
                        mode={"inline"}
                        style={{height: "calc(100% - " + (isShowSearchMenu ? 36 : 0) + "px)"}}
                        inlineIndent={10}
                        inlineCollapsed={fold}
                        items={menus}
                        onSelect={onSelect}
                        onOpenChange={onOpenChange}
                        selectedKeys={[selectedKey]}
                        openKeys={openKeys}
                    />
                </div>
            </ConfigProvider>
        )
    }, [fold, menus, selectedKey, openKeys, props.themeToken]);

    return (renderLeftMenu);
};

export default coreConnect("menuReducer", "themeReducer")(React.memo(LeftMenu));